# 多元线性回归
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt

a = np.array([[1, 2], [3, 4]])
m = np.mat(a)  # NumPy中创建矩阵需要使⽤mat函数，该函数需要输⼊⼆维数组
print('matrix:\n', m)

# 矩阵转置
print('m.T:\n', m.T)
# 矩阵乘法
print('m * m:\n', m * m)
# 计算矩阵行列式
print('np.linalg.det(m):\n', np.linalg.det(m))
# 求逆矩阵
print('m.I:\n', m.I)


# 线性回归函数
def standRegres(dataSet):
    xMat = np.mat(dataSet.iloc[:, :-1].values)  # 提取特征
    yMat = np.mat(dataSet.iloc[:, -1].values).T  # 提取标签
    xTx = xMat.T * xMat
    if np.linalg.det(xTx) == 0:
        print('This matrix is singular,cannot do inverse')  # 行列式为0,则该矩阵为奇异矩阵,无法求解逆矩阵
        return

    ws = xTx.I * (xMat.T * yMat)
    return ws


rng = np.random.RandomState(1)  # 设置随机种子
x = 5 * rng.rand(100)  # 100个[0,5)的随机数
y = 2 * x - 5 + rng.randn(100)  # 真实规律的标签取值
X = pd.DataFrame(x)
Y = pd.DataFrame(y)
ex = pd.DataFrame(np.ones([100, 1]))  # 添加一列权威1的列,表示截距
data = pd.concat([ex, X, Y], axis=1)

ws = standRegres(data)
print('ws', ws)

yhat = data.iloc[:, :-1].values * ws  # 预测标签值
plt.plot(data.iloc[:, 1], data.iloc[:, 2], 'o')  # 原始数据点
plt.plot(data.iloc[:, 1], yhat)  # 拟合直线

y = data.iloc[:, -1].values
yhat = yhat.flatten()
SSE = np.power(yhat - y, 2).sum()
print('SSE:\n', SSE)


def sseCal(dataSet, regres):
    n = dataSet.shape[0]
    y = dataSet.iloc[:, -1].values
    ws = regres(dataSet)
    yhat = dataSet.iloc[:, :-1].values * ws
    yhat = yhat.flatten()
    SSE = np.power(yhat - y, 2).sum()
    return SSE


SSE = sseCal(data, standRegres)
print('SSE:\n', SSE)

sse = sseCal(data, standRegres)
y = data.iloc[:, -1].values
sst = np.power(y - y.mean(), 2).sum()
print(1 - sse / sst)


def rSquare(dataSet, regres):
    sse = sseCal(dataSet, regres)
    y = dataSet.iloc[:, -1].values
    sst = np.power(y - y.mean(), 2).sum()
    return 1 - sse / sst


res = rSquare(data, standRegres)
print('rSquare:\n', res)
